import time
import datetime
from django.db.models import F, Q, Sum
from django.db import models
from django.utils import timezone
from django.contrib.auth import get_user_model
from core.tools.func_utils import FuncUtils
from core.tools.encryption import hashlib_md5
from django.db.models.signals import pre_save
from django.dispatch import receiver

from .client import get_czb_api
from core.wchat.WXInstance import KLBWxBase

User = get_user_model()


# 期限时间
class ExpiryDatePrice(models.Model):
    month = models.IntegerField(verbose_name="月")
    price = models.IntegerField(verbose_name="价格", help_text="以分为单位")
    old_price = models.IntegerField(verbose_name="原价", help_text="以分为单位", default=0)
    name = models.CharField(verbose_name="名称", default="会员卡", max_length=16)

    class Meta:
        verbose_name = "购买权限期限时间"
        verbose_name_plural = verbose_name


class GasStationInfo(models.Model):
    gas_type = ((1, "中石油"), (2, "中石化"), (3, "壳牌"), (4, "其他"))
    gasId = models.CharField(max_length=51, db_index=True, verbose_name="加油站id", unique=True)
    gasName = models.CharField(max_length=160, db_index=True, verbose_name="油站名称", blank=True, null=True)
    gasType = models.IntegerField(choices=gas_type, db_index=True, verbose_name="品牌", blank=True, null=True)
    gasLogoSmall = models.CharField(verbose_name="小Logo图片链接", max_length=512, blank=True, null=True)
    gasLogoBig = models.CharField(verbose_name="大Logo图片链接", max_length=512, blank=True, null=True)
    gasAddress = models.CharField(verbose_name="加油站详情地址", max_length=128, blank=True, null=True)
    gasAddressLongitude = models.FloatField(verbose_name="经度", db_index=True, blank=True, null=True)
    gasAddressLatitude = models.FloatField(verbose_name="纬度", db_index=True, blank=True, null=True)
    provinceCode = models.IntegerField(verbose_name="省份编码", db_index=True, blank=True, null=True)
    cityCode = models.IntegerField(verbose_name="城市编码", db_index=True, blank=True, null=True)
    countyCode = models.IntegerField(verbose_name="县编码", db_index=True, blank=True, null=True)
    provinceName = models.CharField(verbose_name="省", max_length=64, db_index=True, blank=True, null=True)
    cityName = models.CharField(verbose_name="市", max_length=64, db_index=True, blank=True, null=True)
    countyName = models.CharField(verbose_name="区", max_length=64, db_index=True, blank=True, null=True)
    isInvoice = models.IntegerField(verbose_name="发票", blank=True, null=True)
    create_time = models.DateTimeField(default=timezone.now)
    update_time = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = "油站信息"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "%s:%s" % (self.gasName, self.id)


# 油枪号信息
class GunNos(models.Model):
    oil = models.ForeignKey("OilInfo", verbose_name="油号信息")
    gunNo = models.IntegerField(verbose_name="油枪号", db_index=True)

    class Meta:
        verbose_name = "油枪号信息"
        verbose_name_plural = verbose_name


class OilInfoManager(models.Manager):
    def update_oil_data(self, gas_instance, content):
        oilPriceList = content.get("oilPriceList")
        new_oil_price_list = []
        for oil in oilPriceList:
            priceYfq = float(oil.get("priceYfq")) + 0.00  # 加7分钱
            priceGun = float(oil.get("priceGun"))
            gunNos = oil.get("gunNos")
            defaults = {
                "oilName": oil.get("oilName"),
                "priceYfq": priceYfq,
                "priceGun": priceGun,
                "priceOfficial": oil.get("priceOfficial"),
                "oilType": oil.get("oilType"),
            }
            others = {"oilNo": oil.get("oilNo"), "gs_station": gas_instance}
            oli_instance, status = self.update_or_create(
                defaults=defaults,
                **others
            )
            discount = 1
            # 小于加油站油枪价
            less_than_gun = priceYfq <= priceGun
            if less_than_gun and discount and gunNos:
                for gun in gunNos:
                    GunNos.objects.get_or_create(oil=oli_instance, gunNo=gun.get("gunNo"))
                new_oil_price_list.append(oil)
        return new_oil_price_list


class OilInfo(models.Model):
    oil_type = ((1, "汽油"), (2, "柴油"), (3, "天然气"))
    gs_station = models.ForeignKey("GasStationInfo", verbose_name="对应的加油站")
    oilNo = models.IntegerField(verbose_name="油号编码", db_index=True)
    oilName = models.CharField(verbose_name="油号名称", max_length=32)
    oilType = models.IntegerField(verbose_name="油号类别", choices=oil_type)
    priceYfq = models.FloatField(verbose_name="车主邦价格")
    priceGun = models.FloatField(verbose_name="枪价")
    priceOfficial = models.FloatField(verbose_name="国标价")
    create_time = models.DateTimeField(default=timezone.now)
    update_time = models.DateTimeField(auto_now=True)
    objects = OilInfoManager()

    class Meta:
        verbose_name = "油信息"
        verbose_name_plural = verbose_name


class BankServerFeeManager(models.Manager):
    def get_instance(self, pay_type):
        not_time = datetime.datetime.now()
        return self.filter(pay_type=pay_type, fix_time__lte=not_time).first()


class BankServerFee(models.Model):
    payType = ((0, "未付"),
               (1, "微信支付"),
               (2, "api支付,对方收款"),
               (3, "通联支付"),
               (4, "银联支付"),
               (5, "银联小程序支付"),
               (6, "中信银行"),
               (7, "银联APP支付宝支付"),
               )
    pay_type = models.IntegerField(choices=payType, verbose_name="支付类型", default=0)
    fix_time = models.DateTimeField(default=timezone.now, verbose_name="修改时间")
    rate = models.DecimalField(max_digits=6, decimal_places=5)
    objects = BankServerFeeManager()

    class Meta:
        verbose_name = "支付通道费"
        verbose_name_plural = verbose_name


class OrdersManager(models.Manager):
    def get_total_data(self, user):
        """
        获取实付订单总和，和应付订单总和
        :return:
        """
        queryset = self.filter(Q(order_type=1), ~Q(pay_type=0), user=user)
        amountGun = queryset.aggregate(sum_amountGun=Sum("amountGun"))
        payment = queryset.aggregate(sum_payment=Sum("payment"))
        discount = amountGun - payment
        data = {"sum_amount_gun": amountGun, "sum_payment": payment, "discount": discount}
        return data

    def admin_total_data(self, queryset):
        """
        计算应该实际到账多少钱
        :return:
        """
        payment = queryset.aggregate(sum_payment=Sum("payment"))  # 实际支付金额
        payment_czb = queryset.aggregate(sum_payment_czb=Sum("payment_czb"))  # 要给车主邦的钱
        bank_server_fee = queryset.aggregate(sum_bank_server_fee_value=Sum("bank_server_fee_value"))
        payment = payment.get("sum_payment") if payment.get("sum_payment") else 0
        payment_czb = payment_czb.get("sum_payment_czb") if payment_czb.get("sum_payment_czb") else 0
        bank_server_fee = bank_server_fee.get("sum_bank_server_fee_value") if bank_server_fee.get(
            "sum_bank_server_fee_value") else 0
        true_income = payment - bank_server_fee
        return {"payment": payment, "payment_czb": payment_czb, "true_income": true_income}

    def refund_total_data(self, queryset):
        refund_queryset = queryset.filter(result=2)
        refund_payment_czb = refund_queryset.aggregate(sum_payment_czb=Sum("payment_czb"))  # 退了的钱
        refund_payment_czb = refund_payment_czb.get("sum_payment_czb") if refund_payment_czb.get(
            "sum_payment_czb") else 0
        return refund_payment_czb

class Orders(models.Model):
    payType = ((0, "未付"),
               (1, "微信支付"),
               (2, "api支付,对方收款"),
               (3, "通联支付"),
               (4, "银联支付"),
               (5, "银联小程序支付"),
               (6, "中信银行"),
               (7, "银联APP支付宝支付"),
               (41, "银联微信支付"),
               )
    orderStatus = (
        (0, "未支付"), (1, "支付成功"), (2, "已退款"), (3, "其他"), (4, "支付通道未退款"), (5, "申请退款已提交"), (6, "退款失败"), (101, "订单取消"),
        (500, "提交返回失败"))
    # 车主邦订单状态  0:未支付;1:已支付;4:退款中;5:已退款;6:退款失败;7: 已取消;
    czbUpOrderStatusMap = {0: 0, 1: 1, 4: 5, 6: 6, 7: 101, 5: 2}
    # (0, "未支付"), (1, "支付成功"), (2, "已退款"), (3, "其他"), (4, "支付通道未退款"), (5, "申请退款已提交"), (101, "订单取消"),
    #    (500, "提交车主邦返回失败"))
    orderType = ((1, "加油"), (2, "购买权益"),)
    czbPayStatus = ((0, "未通知付款"), (1, "已通知付款"), (500, "车主邦返回失败"),)
    expiry_date = models.ForeignKey("ExpiryDatePrice", verbose_name="有效期", blank=True, null=True)
    pay_type = models.IntegerField(choices=payType, verbose_name="支付类型", default=0)
    order_type = models.IntegerField(choices=orderType, verbose_name="订单类型", default=1, db_index=True)
    user = models.ForeignKey(User, verbose_name="用户", related_name="user_orders_set")
    refund = models.OneToOneField("supply_order.RefundRecord", verbose_name="退款详情", blank=True, null=True)
    gas = models.ForeignKey("GasStationInfo", verbose_name="油站id", blank=True, null=True)
    gunNo = models.ForeignKey("GunNos", verbose_name="油枪信息", blank=True, null=True)
    amountGun = models.DecimalField(verbose_name="订单总金额, 用户输入价格", max_digits=6, decimal_places=2, blank=True, null=True)
    priceGun = models.DecimalField(verbose_name="下单时实时枪价", max_digits=6, decimal_places=2, blank=True, null=True)
    payment_czb = models.DecimalField(verbose_name="车主邦金额", max_digits=6, decimal_places=2, blank=True,
                                      null=True)
    payment = models.DecimalField(verbose_name="我方实付金额", max_digits=6, decimal_places=2, blank=True,
                                  null=True)
    priceUnit = models.DecimalField(verbose_name="下单时享有单价，车主邦价格", max_digits=6, decimal_places=2, blank=True,
                                    null=True)
    litre = models.DecimalField(verbose_name="当前订单升数", max_digits=6, decimal_places=2, blank=True, null=True)
    outerOrderId = models.CharField(verbose_name="我方订单号", max_length=64, db_index=True)
    out_trade_no = models.CharField(verbose_name="支付订单号", max_length=80, db_index=True, blank=True, null=True)
    orderId = models.CharField(verbose_name="车主邦订单号", max_length=64, db_index=True, blank=True, null=True)
    orderSn = models.CharField(verbose_name="支付回告唯一标识", max_length=64, db_index=True, blank=True, null=True)
    create_time = models.DateTimeField(verbose_name="创建时间", default=timezone.now)
    result = models.IntegerField(verbose_name="支付结果", db_index=True, choices=orderStatus, default=0)
    pay_time = models.DateTimeField(verbose_name="支付时间", blank=True, null=True)
    update_time = models.DateTimeField(verbose_name="状态更新时间", auto_now=True)
    message = models.TextField(verbose_name="返回内容", blank=True, null=True)
    czb_pay_status = models.IntegerField(verbose_name="车主邦支付结果", choices=czbPayStatus, default=0)
    channel = models.ForeignKey("ApiChannel", blank=True, null=True, related_name="channel_order_set")
    czb_app_key = models.CharField(blank=True, null=True, verbose_name="车主邦渠道", help_text="方便记录当时用的哪套参数", max_length=20)
    oilNo = models.CharField(verbose_name="油号编码", max_length=8, blank=True, null=True)
    oilType = models.IntegerField(verbose_name="油类型", blank=True, null=True, choices=OilInfo.oil_type)
    gunNumber = models.CharField(verbose_name="油枪编号", max_length=8, blank=True, null=True)
    oilName = models.CharField(verbose_name="油号编码", max_length=8, blank=True, null=True)
    server_fee = models.DecimalField(verbose_name="服务费", max_digits=6, decimal_places=2, blank=True, null=True)
    bank_server_fee = models.ForeignKey("BankServerFee", verbose_name="通道费", blank=True, null=True)
    bank_server_fee_value = models.DecimalField(verbose_name="通道费", default=0, max_digits=5, decimal_places=2)
    objects = OrdersManager()

    class Meta:
        verbose_name = "订单"
        verbose_name_plural = verbose_name

    def update_pay_result(self, result, pay_type=1):
        now_time = datetime.datetime.now()
        if result == 1:
            self.pay_time = now_time
        self.result = result
        self.update_time = now_time
        czb_api = get_czb_api(self.channel.app_key)
        token = czb_api.get_token_from_mc(self.user.mobile)
        response = czb_api.order_pay(self.orderSn, int(self.payment_czb * 100), "200", token)
        if response == 200:
            self.czb_pay_status = 1
        else:
            self.czb_pay_status = response
        bank_server_instance = BankServerFee.objects.filter(pay_type=pay_type, fix_time__lte=now_time).order_by(
            "-fix_time").first()
        self.pay_type = pay_type
        self.bank_server_fee = bank_server_instance
        if bank_server_instance:
            self.bank_server_fee_value = bank_server_instance.rate * self.payment
        else:
            self.bank_server_fee_value = 0
        self.save()

    def update_pay_info(self, out_trade_no=None, pay_type=1):
        """
        更新
        :param pay_type:
        :return:
        """
        self.out_trade_no = out_trade_no
        self.pay_type = pay_type
        if out_trade_no:
            self.out_trade_no = out_trade_no
        else:
            self.out_trade_no = FuncUtils().unique_value
        self.save()
        return self

    def czb_update_out_trade_no(self, out_trade_no=None):
        if out_trade_no:
            self.out_trade_no = out_trade_no
        else:
            self.out_trade_no = FuncUtils().unique_value
        self.save()
        return self.out_trade_no

    def __str__(self):
        return self.id


class GroupChatQr(models.Model):
    image = models.ImageField(verbose_name="群聊图片", upload_to="GroupChatQr/")
    expire_time = models.DateTimeField(verbose_name="有效期", auto_now=True)

    class Meta:
        verbose_name = "群聊二维码"
        verbose_name_plural = verbose_name

    def kf_send_image(self, openid):
        res = KLBWxBase.upload_file("image", self.image.path)
        media_id = res.get("media_id")
        KLBWxBase.send_image(openid, media_id)


# 渠道充值记录
class RechargeRecord(models.Model):
    value = models.IntegerField(verbose_name="充值金额", help_text="以分为单位")
    create_time = models.DateTimeField(verbose_name="充值时间", auto_now_add=True)
    channel = models.ForeignKey("ApiChannel", verbose_name="充值渠道")

    class Meta:
        verbose_name = "渠道充值记录"
        verbose_name_plural = verbose_name

        # def save(self, force_insert=False, force_update=False, using=None,
        #          update_fields=None):
        #     if self._state.adding:
        #         instance = super(RechargeRecord, self).save()
        #         self.channel.balance = F("balance") + self.value
        #         self.channel.save()
        #         return instance
        #     else:
        #         pre_save.connect(ApiChannel().update_balance, sender="czb.RechargeRecord")
        #         pre_save.send("czb.RechargeRecord")


# 对外输出渠道
class ApiChannel(models.Model):
    channelType = ((1, "API预付费"), (2, "H5会员卡"), (3, "H5"), (4, "API-非预付"),)
    app_key = models.CharField(max_length=64, db_index=True)
    app_secret = models.CharField(max_length=64)
    pay_type = models.CharField(max_length=62, blank=True, null=True, verbose_name="要使用的支付方式")
    name = models.CharField(max_length=64, verbose_name="渠道名称")
    create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
    status = models.BooleanField(verbose_name="正常使用", default=True)
    balance = models.IntegerField(verbose_name="余额", default=0)
    callback = models.CharField(verbose_name="回调地址", blank=True, null=True, max_length=256)
    channel_type = models.IntegerField(verbose_name="渠道类型", choices=channelType, default=1)
    channel_menus = models.ManyToManyField("ChannelMenus", related_name="api_channel_menus_set", blank=True, null=True)

    class Meta:
        verbose_name = "API渠道"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        if self._state.adding:
            self.app_secret = hashlib_md5(self.app_key + str(time.time()))
        return super(ApiChannel, self).save()

    @receiver(pre_save, sender="czb.RechargeRecord")
    def update_balance(**kwargs):
        recharge_instance = kwargs.get("instance")
        api_channel_instance = recharge_instance.channel
        if recharge_instance._state.adding:
            api_channel_instance.balance = F("balance") + recharge_instance.value
            api_channel_instance.save()
        else:
            old_recharge_instance = kwargs.get('sender').objects.get(id=recharge_instance.id)
            value = recharge_instance.value - old_recharge_instance.value
            if api_channel_instance.balance + value < 0:
                raise Exception("按现在的数据更新,余额将变为负值,产品无法使用")
            api_channel_instance.balance = F("balance") + value
            api_channel_instance.save()


# 用户菜单
class ChannelMenus(models.Model):
    name = models.CharField(verbose_name="名称", max_length=16)
    key = models.CharField(verbose_name="标识", max_length=16, blank=True, null=True)

    class Meta:
        verbose_name = "用户菜单"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 对应车主邦渠道
class ChannelRiseInPrice(models.Model):
    channel = models.OneToOneField("ApiChannel", verbose_name="渠道")
    czb_app_secret = models.CharField(verbose_name="secret", blank=True, null=True, max_length=32)
    czb_channelId = models.CharField(verbose_name="channelId", blank=True, null=True, max_length=64)
    czb_key = models.CharField(verbose_name="key", blank=True, null=True, help_text="czb_key", max_length=64)
    czb_payCode = models.CharField(verbose_name="payCode", blank=True, null=True, max_length=64)
    desc = models.CharField(max_length=16, verbose_name="功能描述", blank=True, null=True)

    class Meta:
        verbose_name = "对应车主邦渠道"
        verbose_name_plural = verbose_name

    def __str__(self):
        return "%s:%s" % (self.channel.name, self.czb_key)


class ReceiptTicket(models.Model):
    ticketType = ((0, "公司"), (1, "个人"))
    user = models.ForeignKey(User, verbose_name="用户", related_name="user_ticket_set")
    title = models.IntegerField(verbose_name="类型", choices=ticketType)
    buyerTaxNo = models.CharField(verbose_name="购方纳税人识别号", max_length=64, blank=True, null=True)
    buyerName = models.CharField(verbose_name="购方单位名称", max_length=64, blank=True, null=True)
    buyerNamePeople = models.CharField(verbose_name="购方单位名称（个人）", max_length=64, blank=True, null=True)
    buyerAddressPhone = models.TextField(verbose_name="购方地址及电话", blank=True, null=True)
    buyerBankAccount = models.CharField(verbose_name="购方开户行及账号", blank=True, null=True, max_length=64)
    buyerEmail = models.CharField(verbose_name="购方客户邮箱", max_length=64)
    invoiceContent = models.IntegerField(default=1, verbose_name="开票类型")
    default = models.BooleanField(default=True, verbose_name="是否是默认开票信息", db_index=True)
    status = models.BooleanField(default=True, verbose_name="状态", db_index=True)

    class Meta:
        verbose_name = "车主邦发票"
        verbose_name_plural = verbose_name


class OrderTicket(models.Model):
    order = models.OneToOneField(Orders, verbose_name="订单")
    user = models.ForeignKey(User, verbose_name="用户", related_name="user_order_ticket_set")
    title = models.IntegerField(verbose_name="类型", choices=ReceiptTicket.ticketType)
    buyerTaxNo = models.CharField(verbose_name="购方纳税人识别号", max_length=64, blank=True, null=True)
    buyerName = models.CharField(verbose_name="购方单位名称", max_length=64, blank=True, null=True)
    buyerAddressPhone = models.TextField(verbose_name="购方地址及电话", blank=True, null=True)
    buyerBankAccount = models.CharField(verbose_name="购方开户行及账号", blank=True, null=True, max_length=64)
    buyerEmail = models.CharField(verbose_name="购方客户邮箱", max_length=64)
    invoiceContent = models.IntegerField(default=1, verbose_name="开票类型")
    serialNo = models.CharField(verbose_name="开票流水号", max_length=64)
    create_time = models.DateTimeField(verbose_name="创建时间", default=timezone.now)

    class Meta:
        verbose_name = "开票信息"
        verbose_name_plural = verbose_name


# 关注加油站
class GasFollow(models.Model):
    gas = models.ForeignKey(GasStationInfo, verbose_name="加油站")
    user = models.ForeignKey(User, verbose_name="用户")
    price = models.DecimalField(verbose_name="价格", max_digits=6, decimal_places=2)
    oilNo = models.IntegerField(default=92, db_index=True)

    class Meta:
        verbose_name = "关注加油站"
        verbose_name_plural = verbose_name


class ChannelPriceManager(models.Manager):
    def get_server_fee(self, channel, amountGun):
        try:
            price_obj = ChannelPrice.objects.get(channel=channel, start_m__lt=amountGun, end_m__gte=amountGun)
            server_fee = price_obj.server_fee
        except Exception as e:
            print("%s, %s 没在价格区间里" % (channel.app_key, amountGun))
            server_fee = 0
        return server_fee


# 加价
class ChannelPrice(models.Model):
    """
    按渠道加价
    """
    channel = models.ForeignKey(ApiChannel, verbose_name="渠道")
    start_m = models.DecimalField(verbose_name="加价区间小", max_digits=6, decimal_places=2)
    end_m = models.DecimalField(verbose_name="加价区间大", max_digits=6, decimal_places=2)
    server_fee = models.DecimalField(verbose_name="服务费", max_digits=6, decimal_places=2)
    objects = ChannelPriceManager()

    class Meta:
        verbose_name = "渠道加价"
        verbose_name_plural = verbose_name
